/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.service.time.ntptime;

import java.net.DatagramPacket;
import java.net.InetAddress;

/**
 * This class encapsulates a NtpDatagram. See rfc2030 for more
 * details.
 * @author Hasan Bulut - hbulut@indiana.edu
 */
public class NtpDatagramPacket {
  //~ Instance fields ----------------------------------------------------------

  private DatagramPacket ntpPacket;
  private NtpInfo        ntpInfo = new NtpInfo();
  private NtpTimestamp originateTimeStamp = new NtpTimestamp();
  private NtpTimestamp receiveTimeStamp   = new NtpTimestamp();
  private NtpTimestamp receptionTimeStamp = new NtpTimestamp();
  private NtpTimestamp referenceTimeStamp = new NtpTimestamp();
  private NtpTimestamp transmitTimeStamp  = new NtpTimestamp();

  //~ Constructors -------------------------------------------------------------

  /**
   * Constructs a NtpDatagram with only the transmit timestamp
   * filled in (set to the current time).
   * @param header NtpHeader
   * @param iaddr InetAddress - InetAddress of the server
   * @param iport int - port number of the server
   */
  public NtpDatagramPacket(NtpHeader header, InetAddress iaddr, int iport) {
    byte[] buffer = new byte[NtpOffset.NTPDataLength];
    byte[] temp = new byte[NtpOffset.offReferenceTimestamp -
                  NtpOffset.offHeader];
    temp = header.getHeaderData();
    for (int i = NtpOffset.offHeader; i < NtpOffset.offReferenceTimestamp;
         i++) {
      buffer[i] = temp[i - NtpOffset.offHeader];
    }
    for (int i = NtpOffset.offReferenceTimestamp; i < NtpOffset.NTPDataLength;
         i++) {
      buffer[i] = 0;
    }
    byte[]       temp2;
    NtpTimestamp ntpTS = new NtpTimestamp();
    temp2 = ntpTS.getTimestampData();
    for (int i = NtpOffset.offTransmitTimestamp; i < NtpOffset.NTPDataLength;
         i++) {
      buffer[i] = temp2[i - NtpOffset.offTransmitTimestamp];
    }
    ntpPacket = new DatagramPacket(buffer, NtpOffset.NTPDataLength, iaddr, iport);
  }

  /**
   * Constructs a NtpDatagram with only the transmit timestamp
   * filled in (set to the current time). The header is set to
   * NtpHeader.defaultHeader.
   * @param iaddr InetAddress - InetAddress of the server
   * @param iport int - port number of the server
   */
  public NtpDatagramPacket(InetAddress iaddr, int iport) {
    this(NtpHeader.defaultHeader, iaddr, iport);
  }

  /**
   * Constructs an uninitialized NtpDatagram from a UDP datagram.
   */
  public NtpDatagramPacket() {
    byte[] buffer = new byte[NtpOffset.NTPDataLength];
    ntpPacket = new DatagramPacket(buffer, NtpOffset.NTPDataLength);
  }

  /**
   * Sets the UDP packet to the given one.
   * @param dp - UDP datagram packet
   */
  public NtpDatagramPacket(DatagramPacket dp) {
    this.ntpPacket = dp;
  }

  //~ Methods ------------------------------------------------------------------

  /**
   * Gets the UDP datagram associated to NtpDatagramPacket.
   * @return DatagramPacket - UDP datagram packet
   */
  public DatagramPacket getDatagramPacket() {
    return ntpPacket;
  }

  /**
   * Gets the header associated to a NtpDatagramPacket.
   * @return NtpHeader - Header of the NTP packet
   */
  public NtpHeader getHeader() {
    byte[] buffer = ntpPacket.getData();
    byte[] temp = new byte[NtpOffset.offReferenceTimestamp -
                  NtpOffset.offHeader];
    for (int i = NtpOffset.offHeader; i < NtpOffset.offReferenceTimestamp;
         i++) {
      temp[i - NtpOffset.offHeader] = buffer[i];
    }
    return new NtpHeader(temp);
  }

  /**
   * Gets the information in a NtpDatagramPacket.
   * @return NtpInfo - values of the NtpInfo object is set and returned
   */
  public NtpInfo getInfo() {
    setNtpTimestamps();
    NtpHeader h = getHeader();
    ntpInfo.serverAddress       = ntpPacket.getAddress();
    ntpInfo.leapYearIndicator   = h.getLeapIndicator();
    ntpInfo.versionNumber       = h.getVersionNumber();
    ntpInfo.stratum             = h.getStratum();
    ntpInfo.mode                = h.getMode();
    ntpInfo.pollInterval        = h.getPollInterval();
    ntpInfo.precision           = h.getPrecision();
    ntpInfo.rootDelay           = h.getRootDelay();
    ntpInfo.rootDispersion      = h.getRootDispersion();
    ntpInfo.referenceIdentifier = h.getReferenceID();
    ntpInfo.referenceTimeStamp  = getReferenceTimeStamp();
    ntpInfo.originate           = getOriginateTimeStamp().getTimeInMilliSeconds();
    ntpInfo.receive             = getReceiveTimeStamp().getTimeInMilliSeconds();
    ntpInfo.transmit            = getTransmitTimeStamp().getTimeInMilliSeconds();
    ntpInfo.reception           = getReceptionTimeStamp().getTimeInMilliSeconds();
    ntpInfo.roundTripDelay      = ntpInfo.receive - ntpInfo.originate +
                                  ntpInfo.reception - ntpInfo.transmit;
    ntpInfo.offset              = (ntpInfo.receive - ntpInfo.originate -
                                  ntpInfo.reception + ntpInfo.transmit) / 2;
    return ntpInfo;
  }

  /**
   * sets ReferenceTimeStamp, OriginateTimeStamp, ReceiveTimeStamp, TransmitTimeStamp
   * using the data value of the Ntp Packet
   */
  public void setNtpTimestamps() {
    byte[] buffer = ntpPacket.getData();
    referenceTimeStamp.setTimestamp(NtpOffset.offReferenceTimestamp, buffer);
    originateTimeStamp.setTimestamp(NtpOffset.offOriginateTimestamp, buffer);
    receiveTimeStamp.setTimestamp(NtpOffset.offReceiveTimestamp, buffer);
    transmitTimeStamp.setTimestamp(NtpOffset.offTransmitTimestamp, buffer);
  }

  /**
   * Gets the originate timestamp.
   * @return NtpTimestamp
   */
  public NtpTimestamp getOriginateTimeStamp() {
    return originateTimeStamp;
  }

  /**
   * Gets the receive timestamp.
   * @return NtpTimestamp
   */
  public NtpTimestamp getReceiveTimeStamp() {
    return receiveTimeStamp;
  }

  /**
   * Gets the reception timestamp.
   * @return NtpTimestamp
   */
  public NtpTimestamp getReceptionTimeStamp() {
    return receptionTimeStamp;
  }

  /**
   * Gets the reference timestamp.
   * @return NtpTimestamp
   */
  public NtpTimestamp getReferenceTimeStamp() {
    return referenceTimeStamp;
  }

  /**
   * Gets the transmit timestamp.
   * @return NtpTimestamp
   */
  public NtpTimestamp getTransmitTimeStamp() {
    return transmitTimeStamp;
  }

  /**
   * Gets NtpDatagramPacket in String format. String includes the followings:
   * Header, ReferenceTimeStamp, OriginateTimeStamp, ReceiveTimeStamp, TransmitTimeStamp
   * @return String - String representation of NtpDatagramPacket
   */
  public String toString() {
    String s;
    s = "Header : ";
    s = s + getHeader();
    s = s + "\n";
    s = s + "ReferenceTimeStamp : ";
    s = s + getReferenceTimeStamp();
    s = s + "\n";
    s = s + "OriginateTimeStamp : ";
    s = s + getOriginateTimeStamp();
    s = s + "\n";
    s = s + "ReceiveTimeStamp : ";
    s = s + getReceiveTimeStamp();
    s = s + "\n";
    s = s + "TransmitTimeStamp : ";
    s = s + getTransmitTimeStamp();
    return s;
  }

  /**
   * Sets the reception timestamp to the given NtpTimestamp object.
   * @param receptionTimeStamp NtpTimestamp
   */
  void setReceptionTimeStamp(NtpTimestamp receptionTimeStamp) {
    this.receptionTimeStamp = receptionTimeStamp;
  }
}
